package com.blumov.fastbox.infrastructure.persistence.hibernate.compra;

import java.util.List;
import java.util.UUID;

import org.hibernate.Criteria;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import com.blumov.fastbox.domain.model.compra.Pedido;
import com.blumov.fastbox.domain.model.compra.PedidoId;
import com.blumov.fastbox.domain.model.compra.PedidoRepository;
import com.blumov.fastbox.domain.model.compra.enums.EstadoTransaccion;
import com.blumov.fastbox.infrastructure.persistence.dataaccess.simpledao.SimpleDAO;

/**
 * Una implementacion de {@link PedidoRepository} usando Hibernate.
 * 
 * @author Bruno Masci
 */
public class PedidoRepositoryHibernate implements PedidoRepository {

	/**
	 * DAO para operar con la DB
	 */
	private SimpleDAO simpleDAO;

	
	private PedidoRepositoryHibernate() {
	}
	
	/**
	 * @see com.blumov.fastbox.domain.model.compra.PedidoRepository#find(com.blumov.fastbox.domain.model.compra.PedidoId)
	 */
	public Pedido find(PedidoId pedidoId) {	    
	    Criteria criteria = simpleDAO.createCriteria(Pedido.class);
	    criteria.add(Expression.eq("pedidoId.id", pedidoId.idString()));
	    Pedido pedido = (Pedido) criteria.uniqueResult();
	    
	    // Null Object pattern
	    return (pedido == null) ? Pedido.NONE : pedido;
	}

	/**
	 * @see com.blumov.fastbox.domain.model.compra.PedidoRepository#traerSiguientePedido()
	 */
	@SuppressWarnings("unchecked")
	public Pedido traerSiguientePedido() {
		Pedido pedido = Pedido.NONE;
		Criteria criteria = simpleDAO.createCriteria(Pedido.class);
		criteria.add(Expression.eq("estadoTransaccion", EstadoTransaccion.PENDIENTE));
		criteria.addOrder(Order.asc("id"));
		List<Pedido> pedidos = criteria.list();
		if (pedidos != null && pedidos.size() > 0) {
			pedido = pedidos.get(0);
		}
		return pedido;
	}

	/**
	 * @see com.blumov.fastbox.domain.model.compra.PedidoRepository#pedidosParaCocinar()
	 */
	@SuppressWarnings("unchecked")
	public List<Pedido> pedidosParaCocinar() {
		Criteria criteria = simpleDAO.createCriteria(Pedido.class);
		criteria.add(Expression.eq("estadoTransaccion", EstadoTransaccion.COCINANDO));
		criteria.addOrder(Order.asc("id"));
		List<Pedido> pedidosParaCocinar = criteria.list();
		return pedidosParaCocinar;
	}

	/**
	 * @see com.blumov.fastbox.domain.model.compra.PedidoRepository#pedidosListos()
	 */
	@SuppressWarnings("unchecked")
	public List<Pedido> pedidosListos() {
		Criteria criteria = simpleDAO.createCriteria(Pedido.class);
		criteria.add(Expression.eq("estadoTransaccion", EstadoTransaccion.LISTO));
		criteria.addOrder(Order.asc("id"));
		List<Pedido> pedidosListos = criteria.list();
		return pedidosListos;
	}
	
	/**
	 * @see com.blumov.fastbox.domain.model.compra.PedidoRepository#pedidosPendientes()
	 */
	@SuppressWarnings("unchecked")
	public List<Pedido> pedidosPendientes() {
		Criteria criteria = simpleDAO.createCriteria(Pedido.class);
		criteria.add(Restrictions.disjunction()
				.add(Expression.eq("estadoTransaccion", EstadoTransaccion.PENDIENTE))
				.add(Expression.eq("estadoTransaccion", EstadoTransaccion.PREPARANDO))
				.add(Expression.eq("estadoTransaccion", EstadoTransaccion.COCINANDO))
		);
		criteria.addOrder(Order.asc("id"));
		List<Pedido> pedidosListos = criteria.list();
		return pedidosListos;
	}
	
	/**
	 * @see com.blumov.fastbox.domain.model.compra.PedidoRepository#store(com.blumov.fastbox.domain.model.compra.Pedido)
	 */
	public void store(Pedido pedido) {
		this.simpleDAO.save(pedido);
	}

	/**
	 * @see com.blumov.fastbox.domain.model.compra.PedidoRepository#nextPedidoId()
	 */
	public PedidoId nextPedidoId() {
		String random = UUID.randomUUID().toString().toUpperCase();
		return new PedidoId(random.substring(0, random.indexOf("-")));
	}

	/**
	 * Injected by Spring
	 */
	public void setSimpleDAO(SimpleDAO simpleDAO) {
		this.simpleDAO = simpleDAO;
	}
}
